package com.example.gobang.game;

import com.example.gobang.GobangApplication;
import com.example.gobang.model.UserInfo;
import com.example.gobang.model.UserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Room 不是Spring的组件，所以这里不能从获取获取Bean
 * 所以需要手动来注入
 */
@Data
public class Room {
    private String roomId;
    private UserInfo userInfo1;
    private UserInfo userInfo2;

    private Integer white;
    private ObjectMapper objectMapper = new ObjectMapper();

    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;

    private static  final  int MAX_CHAT = 10;
    private int[][] chessBoard;

//    解决线程安全问题的 CopyOnWriteArrayList
   private List<ChattererRequest> chattererRequests;
    //    手动注入
   private OnlineUserManager onlineUserManager;


    private RoomManager roomManager;

    private UserMapper userMapper;

    public Room() {
//        初始化一个随机不重复的房间 id
        roomId = UUID.randomUUID().toString();
        chessBoard = new int[MAX_ROW][MAX_COL];
        onlineUserManager = GobangApplication.context.getBean(OnlineUserManager.class);
        roomManager = GobangApplication.context.getBean(RoomManager.class);
        userMapper = GobangApplication.context.getBean(UserMapper.class);
        chattererRequests = new CopyOnWriteArrayList<>();
    }

    public void putChess(Object payload) throws IOException {
//       1.  先转化为java的请求格式并赋值
        GameRequest request = objectMapper.readValue(payload.toString(), GameRequest.class);
        GameResponse response = new GameResponse();
        int row = request.getRow();
        int col = request.getCol();

//        如果当前位置是玩家一 就为在数组上划分为1 ，否则为 2
        int chess = request.getUserId() == userInfo1.getUserId() ? 1 : 2;

//        2. 填入数据并打印棋盘情况
        if (chessBoard[row][col] != 0) {
            System.out.println("棋盘上已经有棋子， 无法填入!");
            return;
        }
        chessBoard[row][col] = chess;
        printBoard();

        // 处理输赢结果
        int winner = checkWinner(row, col, chess);
        response.setUserId(request.getUserId());
        response.setMessage("putChess");
        response.setWinner(winner);
        response.setRow(row);
        response.setCol(col);

        // 4. 获取Session 并且响应数据返回
        WebSocketSession playerSession1 = onlineUserManager.getFromGameRoom(this.userInfo1.getUserId());
        WebSocketSession playerSession2 = onlineUserManager.getFromGameRoom(this.userInfo2.getUserId());
        if (playerSession1 == null) {
            // 玩家一掉线
            System.out.println("playerSession1：" + userInfo1.getUserName() + "掉线!");
            response.setWinner(userInfo2.getUserId());
        }

        if (playerSession2 == null) {
            // 玩家二掉线
            System.out.println("playerSession2：" + userInfo2.getUserName() + "掉线!");
            response.setWinner(userInfo1.getUserId());
        }
//        谁不掉线就发给谁
        if (playerSession1 != null) {
            playerSession1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
        if (playerSession2 != null) {
            playerSession2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }

        //  计算得分并释放房间对象
        if (response.getWinner() != 0) {
            userMapper.updateWinner(userInfo1.getUserId() == response.getWinner() ? userInfo1 : userInfo2);
            userMapper.updateLoser(userInfo1.getUserId() == response.getWinner() ? userInfo2 : userInfo1);
        }

        if(onlineUserManager.getChatUsers(userInfo1.getUserId()) == null || onlineUserManager.getChatUsers(userInfo2.getUserId()) == null) {
            System.out.println("两人都离线了，开始销毁房间");
            roomManager.remove(roomId, userInfo1.getUserId(), userInfo2.getUserId());
        }

    }

    private int checkWinner(int row, int col, int chess) {
        // 检查横位置
        for (int c = col - 4; c <= col; c++) {
            try {
                if (chessBoard[row][c] == chess &&
                        chessBoard[row][c + 1] == chess &&
                        chessBoard[row][c + 2] == chess &&
                        chessBoard[row][c + 3] == chess &&
                        chessBoard[row][c + 4] == chess) {
//                    如果出现了五子连珠， 就返回当前用户的id
                    return chess == 1 ? userInfo1.getUserId() : userInfo2.getUserId();
                }
            } catch (IndexOutOfBoundsException e) {
                /**
                 *  如果数组越界了，不抛出异常
                 *  而是就跳出当前的情况，继续判断
                 */
                continue;
            }
        }

//        检查列位置
        for (int r = row - 4; r <= row; r++) {
            try {
                if (chessBoard[r][col] == chess &&
                        chessBoard[r + 1][col] == chess &&
                        chessBoard[r + 2][col] == chess &&
                        chessBoard[r + 3][col] == chess &&
                        chessBoard[r + 4][col] == chess) {
                    return chess == 1 ? userInfo1.getUserId() : userInfo2.getUserId();
                }
            } catch (IndexOutOfBoundsException e) {
                /**
                 *  如果数组越界了，不抛出异常
                 *  而是就跳出当前的情况，继续判断
                 */
                continue;
            }
        }

//        检查左上角
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
            try {
                if (chessBoard[r][c] == chess &&
                        chessBoard[r + 1][c + 1] == chess &&
                        chessBoard[r + 2][c + 2] == chess &&
                        chessBoard[r + 3][c + 3] == chess &&
                        chessBoard[r + 4][c + 4] == chess) {
                    return chess == 1 ? userInfo1.getUserId() : userInfo2.getUserId();
                }
            } catch (IndexOutOfBoundsException e) {
                /**
                 *  如果数组越界了，不抛出异常
                 *  而是就跳出当前的情况，继续判断
                 */
                continue;
            }
        }

        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
            try {
                if (chessBoard[r][c] == chess &&
                        chessBoard[r + 1][c - 1] == chess &&
                        chessBoard[r + 2][c - 2] == chess &&
                        chessBoard[r + 3][c - 3] == chess &&
                        chessBoard[r + 4][c - 4] == chess) {
                    return chess == 1 ? userInfo1.getUserId() : userInfo2.getUserId();
                }
            } catch (IndexOutOfBoundsException e) {
                continue;
            }
        }


        // 检查
        return 0;
    }

    private void printBoard() {
        System.out.println("================棋盘打印============================");
        for (int i = 0; i < chessBoard.length; i++) {
            for (int j = 0; j < chessBoard[i].length; j++) {
                System.out.print(chessBoard[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println("==================================================");

    }



    public void displayChatMes(ChattererRequest request) throws IOException {
//        针对当前的room 房间进行加锁
        synchronized (this) {
            if (request == null) {
                System.out.println("room::displayChatMes中的请求为空!");
                return;
            }
//        1. 加入到列表中
            chattererRequests.add(request);

//        2. 构造返回类型
            List<ChattererRequest> ret = new CopyOnWriteArrayList<>();
            ChattererResponse response = new ChattererResponse();

            // 3. 获取Session 并且响应数据返回
            WebSocketSession playerSession1 = onlineUserManager.getChatUsers(this.userInfo1.getUserId());
            WebSocketSession playerSession2 = onlineUserManager.getChatUsers(this.userInfo2.getUserId());


//        4. 分批次返回消息
            int len = chattererRequests.size();
            if (len <= MAX_CHAT) {
                System.out.println("得到的小于5聊天消息的数据量!");
                //            寻找从 0 到 MAX_CHAT
                for (ChattererRequest chattererRequest : chattererRequests) {
                    System.out.println("chattererRequest.getMessage()：" + chattererRequest.getMessage());
                    ret.add(chattererRequest);
                }
            } else {
                System.out.println("得到的大于5聊天消息的数据量!");
//            寻找后五位

                for (int i = len - MAX_CHAT; i < len; i++) {
                    ret.add(chattererRequests.get(i));
                }
            }

            // 设置返回类型并发送
            response.setChatSign("chat");
            response.setMessage(ret);

//        谁不掉线就发给谁
            if (playerSession1 != null) {
                playerSession1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            }
            if (playerSession2 != null) {
                playerSession2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            }

        }


    }
}
